﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml;
using System.Globalization;

namespace GPCodeConjurer
{
	static class ExtensionHelpers
	{
		/// <summary>
		/// correct values of a rectangle with negative width and/or height.
		/// </summary>
		/// <param name="rect"></param>
		/// <returns></returns>
		public static Rectangle Absolute(this Rectangle rect)
		{
			Rectangle newRect = rect;
			if (newRect.Width < 0)
			{
				newRect.X += rect.Width;
				newRect.Width = -rect.Width;
			}
			if (newRect.Height < 0)
			{
				newRect.Y += rect.Height;
				newRect.Height = -rect.Height;
			}
			return newRect;
		}


		/// <summary>
		/// correct values of a rectangle with negative width and/or height.
		/// </summary>
		/// <param name="rect"></param>
		/// <returns></returns>
		public static RectangleF Absolute(this RectangleF rect)
		{
			RectangleF newRect = rect;
			if (newRect.Width < 0)
			{
				newRect.X += rect.Width;
				newRect.Width = -rect.Width;
			}
			if (newRect.Height < 0)
			{
				newRect.Y += rect.Height;
				newRect.Height = -rect.Height;
			}
			if (newRect.X < 0)
				newRect.X = 0;
			if (newRect.Y < 0)
				newRect.Y = 0;
			return newRect;
		}

		public static Point ToPoint(this PointF pt)
		{
			return new Point(Convert.ToInt32(pt.X), Convert.ToInt32(pt.Y));
		}


		internal static void AddRectangularGrabHandles(this Node node)
		{

			node.GrabHandles.Add(
				"NW",
				new GrabHandle(
					node,
					HandleMoveBehavior.NWSE,
					ContentAlignment.BottomRight,
					HandleShape.Rectangle)
				);
			node.GrabHandles.Add(
				"N",
				new GrabHandle(
					node,
					HandleMoveBehavior.Vertically,
					ContentAlignment.BottomCenter)
				);
			node.GrabHandles.Add(
				"NE",
				new GrabHandle(
					node,
					HandleMoveBehavior.NESW,
					ContentAlignment.BottomLeft)
				);
			node.GrabHandles.Add(
				"W",
				new GrabHandle(
					node,
					HandleMoveBehavior.Horizontally,
					ContentAlignment.MiddleRight)
				);
			node.GrabHandles.Add(
				"E",
				new GrabHandle(
					node,
					HandleMoveBehavior.Horizontally,
					ContentAlignment.MiddleLeft)
				);

			node.GrabHandles.Add(
				"SW",
				new GrabHandle(
					node,
					HandleMoveBehavior.NESW,
					ContentAlignment.TopRight)
				);
			node.GrabHandles.Add(
				"S",
				new GrabHandle(
					node,
					HandleMoveBehavior.Vertically,
					ContentAlignment.TopCenter)
				);
			node.GrabHandles.Add(
				"SE",
				new GrabHandle(
					node,
					HandleMoveBehavior.NWSE,
					ContentAlignment.TopLeft)
				);
		}


		internal static XmlElement Serialize(this PointF pt, XmlDocument xmlDoc)
		{
			var n = xmlDoc.CreateElement("PointF");
			n.SetAttribute("x", pt.X.ToString(CultureInfo.InvariantCulture));
			n.SetAttribute("y", pt.Y.ToString(CultureInfo.InvariantCulture));
			return n;
		}

		internal static PointF DeserializePointF(XmlElement element)
		{
			PointF pt = Point.Empty;
			pt.X = float.Parse(element.GetAttribute("x"), CultureInfo.InvariantCulture);
			pt.Y = float.Parse(element.GetAttribute("y"), CultureInfo.InvariantCulture);
			return pt;
		}

		internal static XmlElement Serialize(this RectangleF rect, XmlDocument xmlDoc)
		{
			var n = xmlDoc.CreateElement("RectangleF");
			n.SetAttribute("x", rect.X.ToString(CultureInfo.InvariantCulture));
			n.SetAttribute("y", rect.Y.ToString(CultureInfo.InvariantCulture));
			n.SetAttribute("w", rect.Width.ToString(CultureInfo.InvariantCulture));
			n.SetAttribute("h", rect.Height.ToString(CultureInfo.InvariantCulture));
			return n;
		}

		internal static RectangleF DeserializeRectangleF(XmlElement element)
		{
			RectangleF rect = RectangleF.Empty;
			rect.X = float.Parse(element.GetAttribute("x"), CultureInfo.InvariantCulture);
			rect.Y = float.Parse(element.GetAttribute("y"), CultureInfo.InvariantCulture);
			rect.Width = float.Parse(element.GetAttribute("w"), CultureInfo.InvariantCulture);
			rect.Height = float.Parse(element.GetAttribute("h"), CultureInfo.InvariantCulture);
			return rect;
		}

		/// <summary>
		/// Will append 2 attributes that is the serialized values for StartFigure and CloseFigure.
		/// </summary>
		/// <param name="node"></param>
		/// <param name="xmlDoc"></param>
		/// <returns></returns>
		internal static void SeralizeStartCloseFigure(this Node node, XmlElement element)
		{
			element.SetAttribute("startFigure", node.StartFigure.ToString(CultureInfo.InvariantCulture).ToLower());
			element.SetAttribute("closeFigure", node.CloseFigure.ToString(CultureInfo.InvariantCulture).ToLower());
		}


		internal static void DeseralizeStartCloseFigure(this Node node, XmlElement element)
		{
			node.StartFigure = (element.GetAttribute("startFigure").ToLower() == "true");
			node.CloseFigure = (element.GetAttribute("closeFigure").ToLower() == "true");
		}


		internal static XmlElement AppendElementChild(this XmlElement n, string name, string innerText)
		{
			var newElement = n.AppendChild(n.OwnerDocument.CreateElement(name)) as XmlElement;
			newElement.InnerText = innerText;
			return newElement;
		}

		internal static Color SelectColor(this XmlDocument xmlDoc, string xpath, Color defaultValue)
		{
			var n = xmlDoc.SelectSingleNode(xpath);
			if (n == null || string.IsNullOrEmpty(n.InnerText))
				return defaultValue;
			try
			{
				return ColorTranslator.FromHtml(n.InnerText.ToLower());
			}
			catch
			{
				return defaultValue;
			}
		}


		internal static bool SelectBool(this XmlDocument xmlDoc, string xpath, bool defaultValue)
		{
			var n = xmlDoc.SelectSingleNode(xpath);
			if (n == null || string.IsNullOrEmpty(n.InnerText))
				return defaultValue;
			try
			{
				return (n.InnerText.ToLower() == "true");
			}
			catch
			{
				return defaultValue;
			}
		}



		internal static float SelectFloat(this XmlDocument xmlDoc, string xpath, float defaultValue)
		{
			var n = xmlDoc.SelectSingleNode(xpath);
			if (n == null || string.IsNullOrEmpty(n.InnerText))
				return defaultValue;
			try
			{
				return Convert.ToSingle(n.InnerText);
			}
			catch
			{
				return defaultValue;
			}
		}



		internal static T SelectEnum<T>(this XmlDocument xmlDoc, string xpath, T defaultValue)
		{
			if (typeof(T).BaseType != typeof(Enum))
				throw new ApplicationException(string.Format("Invalid type for casting to enum {0}.", typeof(T)));
			var n = xmlDoc.SelectSingleNode(xpath);
			if (n == null || string.IsNullOrEmpty(n.InnerText))
				return defaultValue;
			try
			{
				return (T)Enum.Parse(typeof(T), n.InnerText, true);
			}
			catch
			{
				return defaultValue;
			}
		}


	}
}
